vmx: Make use of VMX_INSTRUCTION_INFO field to obtain the segment
authorKeir Fraser <keir@xensource.com>
Wed, 27 Jun 2007 19:53:57 +0000 (20:53 +0100)
committerKeir Fraser <keir@xensource.com>
Wed, 27 Jun 2007 19:53:57 +0000 (20:53 +0100)
register of OUTS

Signed-off-by: Weidong Han <weidong.han@intel.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
xen/arch/x86/hvm/vmx/vmcs.c
xen/arch/x86/hvm/vmx/vmx.c
xen/include/asm-x86/hvm/vmx/vmcs.h

index 4c03b31ffca58560229eabe4c224361c64b348a6..ea2afdb72e0e7e436c272e467637eb07d1d74c39 100644 (file)
@@ -43,6 +43,7 @@ u32 vmx_cpu_based_exec_control __read_mostly;
 u32 vmx_secondary_exec_control __read_mostly;
 u32 vmx_vmexit_control __read_mostly;
 u32 vmx_vmentry_control __read_mostly;
+bool_t cpu_has_vmx_ins_outs_instr_info __read_mostly;
 
 static u32 vmcs_revision_id __read_mostly;
 
@@ -133,6 +134,7 @@ void vmx_init_vmcs_config(void)
         vmx_secondary_exec_control = _vmx_secondary_exec_control;
         vmx_vmexit_control         = _vmx_vmexit_control;
         vmx_vmentry_control        = _vmx_vmentry_control;
+        cpu_has_vmx_ins_outs_instr_info = !!(vmx_msr_high & (1U<<22));
     }
     else
     {
@@ -142,6 +144,7 @@ void vmx_init_vmcs_config(void)
         BUG_ON(vmx_secondary_exec_control != _vmx_secondary_exec_control);
         BUG_ON(vmx_vmexit_control != _vmx_vmexit_control);
         BUG_ON(vmx_vmentry_control != _vmx_vmentry_control);
+        BUG_ON(cpu_has_vmx_ins_outs_instr_info != !!(vmx_msr_high & (1U<<22)));
     }
 
     /* IA-32 SDM Vol 3B: VMCS size is never greater than 4kB. */
index 0f361b58771e23a3a73e16dadb8ebcc795554351..4d11313b0885a503bf1b93613ac465dee6314c29 100644 (file)
@@ -1466,16 +1466,34 @@ static void vmx_do_invlpg(unsigned long va)
     paging_invlpg(v, va);
 }
 
-/*
- * get segment for string pio according to guest instruction
- */
-static void vmx_str_pio_get_segment(int long_mode, unsigned long eip,
-                                   int inst_len, enum x86_segment *seg)
+/* Get segment for OUTS according to guest instruction. */
+static enum x86_segment vmx_outs_get_segment(
+    int long_mode, unsigned long eip, int inst_len)
 {
     unsigned char inst[MAX_INST_LEN];
+    enum x86_segment seg = x86_seg_ds;
     int i;
     extern int inst_copy_from_guest(unsigned char *, unsigned long, int);
 
+    if ( likely(cpu_has_vmx_ins_outs_instr_info) )
+    {
+        unsigned int instr_info = __vmread(VMX_INSTRUCTION_INFO);
+
+        /* Get segment register according to bits 17:15. */
+        switch ( (instr_info >> 15) & 7 )
+        {
+        case 0: seg = x86_seg_es; break;
+        case 1: seg = x86_seg_cs; break;
+        case 2: seg = x86_seg_ss; break;
+        case 3: seg = x86_seg_ds; break;
+        case 4: seg = x86_seg_fs; break;
+        case 5: seg = x86_seg_gs; break;
+        default: BUG();
+        }
+
+        goto out;
+    }
+
     if ( !long_mode )
         eip += __vmread(GUEST_CS_BASE);
 
@@ -1484,7 +1502,7 @@ static void vmx_str_pio_get_segment(int long_mode, unsigned long eip,
     {
         gdprintk(XENLOG_ERR, "Get guest instruction failed\n");
         domain_crash(current->domain);
-        return;
+        goto out;
     }
 
     for ( i = 0; i < inst_len; i++ )
@@ -1501,25 +1519,28 @@ static void vmx_str_pio_get_segment(int long_mode, unsigned long eip,
 #endif
             continue;
         case 0x2e: /* CS */
-            *seg = x86_seg_cs;
+            seg = x86_seg_cs;
             continue;
         case 0x36: /* SS */
-            *seg = x86_seg_ss;
+            seg = x86_seg_ss;
             continue;
         case 0x26: /* ES */
-            *seg = x86_seg_es;
+            seg = x86_seg_es;
             continue;
         case 0x64: /* FS */
-            *seg = x86_seg_fs;
+            seg = x86_seg_fs;
             continue;
         case 0x65: /* GS */
-            *seg = x86_seg_gs;
+            seg = x86_seg_gs;
             continue;
         case 0x3e: /* DS */
-            *seg = x86_seg_ds;
+            seg = x86_seg_ds;
             continue;
         }
     }
+
+ out:
+    return seg;
 }
 
 static int vmx_str_pio_check_descriptor(int long_mode, unsigned long eip,
@@ -1532,7 +1553,7 @@ static int vmx_str_pio_check_descriptor(int long_mode, unsigned long eip,
     *base = 0;
     *limit = 0;
     if ( seg != x86_seg_es )
-        vmx_str_pio_get_segment(long_mode, eip, inst_len, &seg);
+        seg = vmx_outs_get_segment(long_mode, eip, inst_len);
 
     switch ( seg )
     {
@@ -1578,7 +1599,7 @@ static int vmx_str_pio_check_descriptor(int long_mode, unsigned long eip,
     }
     *ar_bytes = __vmread(ar_field);
 
-    return !(*ar_bytes & 0x10000);
+    return !(*ar_bytes & X86_SEG_AR_SEG_UNUSABLE);
 }
 
 
index 2513eac43a235a63865ebb7ecbc04b23a49dc9dd..25662f17494ec165bae6f22441ea07ba8741f89e 100644 (file)
@@ -131,6 +131,8 @@ extern u32 vmx_vmentry_control;
 #define SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES 0x00000001
 extern u32 vmx_secondary_exec_control;
 
+extern bool_t cpu_has_vmx_ins_outs_instr_info;
+
 #define cpu_has_vmx_virtualize_apic_accesses \
     (vmx_secondary_exec_control & SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES)
 #define cpu_has_vmx_tpr_shadow \